package cn.tom.tompicturebackend.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.JSONUtil;
import cn.tom.tompicturebackend.exception.BusinessException;
import cn.tom.tompicturebackend.exception.ErrorCode;
import cn.tom.tompicturebackend.exception.ThrowUtils;
import cn.tom.tompicturebackend.mapper.SpaceMapper;
import cn.tom.tompicturebackend.model.dto.space.analyze.*;

import cn.tom.tompicturebackend.model.entity.Picture;
import cn.tom.tompicturebackend.model.entity.Space;
import cn.tom.tompicturebackend.model.entity.User;
import cn.tom.tompicturebackend.model.vo.space.analyze.*;
import cn.tom.tompicturebackend.service.PictureService;
import cn.tom.tompicturebackend.service.SpaceAnalyzeService;
import cn.tom.tompicturebackend.service.SpaceService;
import cn.tom.tompicturebackend.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class SpaceAnalyzeServiceImpl extends ServiceImpl<SpaceMapper, Space> implements SpaceAnalyzeService {

    @Resource
    private UserService userService;

    @Resource
    private SpaceService spaceService;

    @Resource
    private PictureService pictureService;

    @Override
    public SpaceUsageAnalyzeResponse getSpaceUsageAnalyze(SpaceUsageAnalyzeRequest spaceUsageAnalyzeRequest, User loginUser) {

        ThrowUtils.throwIf(spaceUsageAnalyzeRequest == null, ErrorCode.NOT_FOUND_ERROR);
        if(spaceUsageAnalyzeRequest.isQueryAll() || spaceUsageAnalyzeRequest.isQueryPublic()){
            boolean idAdmin = userService.isAdmin(loginUser);
            ThrowUtils.throwIf(!idAdmin, ErrorCode.NOT_FOUND_ERROR);
            //查询所有空间的使用情况
            QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("picSize");
            if(!spaceUsageAnalyzeRequest.isQueryAll()){
                queryWrapper.isNull("spaceId");
            }
            List<Object> pictureObjectList = pictureService.getBaseMapper().selectObjs(queryWrapper);
            long usedSize = pictureObjectList.stream().mapToLong(result -> result instanceof Long ? (Long) result :0).sum();
            long  usedCount = pictureObjectList.size();

            //封装返回结果
            SpaceUsageAnalyzeResponse spaceUsageAnalyzeResponse = new SpaceUsageAnalyzeResponse();
            spaceUsageAnalyzeResponse.setUsedCount(usedCount);
            spaceUsageAnalyzeResponse.setUsedSize(usedSize);
            spaceUsageAnalyzeResponse.setMaxCount(null);
            spaceUsageAnalyzeResponse.setMaxSize(null);
            spaceUsageAnalyzeResponse.setSizeUsageRatio(null);
            spaceUsageAnalyzeResponse.setCountUsageRatio(null);
            return spaceUsageAnalyzeResponse;


        }else{
            // 查询指定空间
            Long spaceId = spaceUsageAnalyzeRequest.getSpaceId();
            ThrowUtils.throwIf(spaceId == null || spaceId <= 0, ErrorCode.PARAMS_ERROR);
            // 获取空间信息
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");

            // 权限校验：仅空间所有者或管理员可访问
            spaceService.checkSpaceAuth(loginUser, space);
            // 构造返回结果
            SpaceUsageAnalyzeResponse response = new SpaceUsageAnalyzeResponse();
            response.setUsedSize(space.getTotalSize());
            response.setMaxSize(space.getMaxSize());
            // 后端直接算好百分比，这样前端可以直接展示
            double sizeUsageRatio = NumberUtil.round(space.getTotalSize() * 100.0 / space.getMaxSize(), 2).doubleValue();
            response.setSizeUsageRatio(sizeUsageRatio);
            response.setUsedCount(space.getTotalCount());
            response.setMaxCount(space.getMaxCount());
            double countUsageRatio = NumberUtil.round(space.getTotalCount() * 100.0 / space.getMaxCount(), 2).doubleValue();
            response.setCountUsageRatio(countUsageRatio);
            return response;

        }

    }



    @Override
    public List<SpaceCategoryAnalyzeResponse> getSpaceCategoryAnalyze(SpaceCategoryAnalyzeRequest spaceCategoryAnalyzeRequest, User loginUser) {
        ThrowUtils.throwIf(spaceCategoryAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);

        checkSpaceAnalyzeAuth(spaceCategoryAnalyzeRequest,loginUser);

        QueryWrapper<Picture> pictureQueryWrapper = new QueryWrapper<>();

        fillAnalyzeQueryWrapper(spaceCategoryAnalyzeRequest,pictureQueryWrapper);

        //分组
        pictureQueryWrapper.select("category As category",
                "count(*) as count",
                "sum(size) as totalSize")
                .groupBy("category");
        //查询并转换结果
        return pictureService.getBaseMapper().selectMaps(pictureQueryWrapper)
                .stream()
                .map(
                        result -> {
                            String category = (String) result.get("category") !=null ? result.get("category").toString() : "未分类";
                            Long count = ((Number) result.get("count")).longValue();
                            Long totalSize = ((Number) result.get("totalSize")).longValue();
                            return new SpaceCategoryAnalyzeResponse(category,count,totalSize);
                        }
                ).collect(Collectors.toList());

    }

    @Override
    public List<SpaceTagAnalyzeResponse> getSpaceTagAnalyze(SpaceTagAnalyzeRequest spaceTagAnalyzeRequest, User loginUser) {
        ThrowUtils.throwIf(spaceTagAnalyzeRequest ==null,ErrorCode.PARAMS_ERROR);

        //检查权限
        checkSpaceAnalyzeAuth(spaceTagAnalyzeRequest,loginUser);

        //构成查询条件
        QueryWrapper<Picture> pictureQueryWrapper = new QueryWrapper<>();
        fillAnalyzeQueryWrapper(spaceTagAnalyzeRequest,pictureQueryWrapper);

        //查询所有符合条件的标签
        pictureQueryWrapper.select("tags");
        List<String> tagsJsonList = pictureService.getBaseMapper().selectObjs(pictureQueryWrapper)
                .stream()
                .filter(ObjUtil::isNotNull)
                .map(Object::toString)
                .collect(Collectors.toList());

        //合并所有的标签并统计使用次数
        Map<String,Long> tagCountMap = tagsJsonList.stream()
                .flatMap(tagsJson -> JSONUtil.toList(tagsJson,String.class).stream())
                .collect(Collectors.groupingBy(tag ->tag,Collectors.counting()));

        //转换为响应对象，按使用次数降序排序
        return tagCountMap.entrySet().stream()
                .sorted((e1,e2) -> Long.compare(e2.getValue(), e1.getValue()))
                .map(entry -> new SpaceTagAnalyzeResponse(entry.getKey(),entry.getValue()))
                .collect(Collectors.toList());


    }

    @Override
    public List<SpaceSizeAnalyzeResponse> getSpaceSizeAnalyze(SpaceSizeAnalyzeRequest spaceSizeAnalyzeRequest, User loginUser) {
        ThrowUtils.throwIf(spaceSizeAnalyzeRequest ==null,ErrorCode.PARAMS_ERROR);

        //检查权限
        checkSpaceAnalyzeAuth(spaceSizeAnalyzeRequest,loginUser);
        //构造查询条件
        QueryWrapper<Picture> pictureQueryWrapper = new QueryWrapper<>();
        fillAnalyzeQueryWrapper(spaceSizeAnalyzeRequest,pictureQueryWrapper);

        //查询所有符合条件的图表大小
        pictureQueryWrapper.select("picSize");
        List<Long> picSizes = pictureService.getBaseMapper().selectObjs(pictureQueryWrapper)
                .stream()
                .map(size -> ((Number) size).longValue())
                .collect(Collectors.toList());

        //定义分段范围，注意是有序map

        Map<String,Long> sizeRangeMap = new LinkedHashMap<>();
        sizeRangeMap.put("<100KB",picSizes.stream().filter(size -> size < 100 * 1024).count());
        sizeRangeMap.put("100KB-500KB",picSizes.stream().filter(size -> size >= 100 * 1024 && size < 500 * 1024).count());
        sizeRangeMap.put("500KB-1MB",picSizes.stream().filter(size -> size >= 500 * 1024 && size < 1024 * 1024).count());
        sizeRangeMap.put("1MB-5MB",picSizes.stream().filter(size -> size >= 1024 * 1024 && size < 5 * 1024 * 1024).count());
        return sizeRangeMap.entrySet().stream()
                .map(entry -> new SpaceSizeAnalyzeResponse(entry.getKey(),entry.getValue()))
                .collect(Collectors.toList());
    }

    @Override
    public List<SpaceUserAnalyzeResponse> getSpaceUserAnalyze(SpaceUserAnalyzeRequest spaceUserAnalyzeRequest, User loginUser) {
        ThrowUtils.throwIf(spaceUserAnalyzeRequest ==null,ErrorCode.PARAMS_ERROR);

        //检查权限
        checkSpaceAnalyzeAuth(spaceUserAnalyzeRequest,loginUser);
        //构造查询条件
        QueryWrapper<Picture> pictureQueryWrapper = new QueryWrapper<>();
        Long userId = spaceUserAnalyzeRequest.getUserId();
        pictureQueryWrapper.eq(ObjUtil.isNotNull(userId),"user_id",userId);
        fillAnalyzeQueryWrapper(spaceUserAnalyzeRequest,pictureQueryWrapper);

        //分析维度:每日、每周、每月
        String timeDimension = spaceUserAnalyzeRequest.getTimeDimension();
        switch (timeDimension){
            case "day":
                pictureQueryWrapper.select("DATE_FORMAT(create_time,'%Y-%m-%d') as period", "count(*) as count");
                break;
            case "week":
                pictureQueryWrapper.select("YEARWEEK(create_time) as period", "count(*) as count");
                break;
            case "month":
                pictureQueryWrapper.select("DATE_FORMAT(create_time,'%Y-%m') as period", "count(*) as count");
                break;
            default:
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"时间维度错误");
        }
        //分组排序
        pictureQueryWrapper.groupBy("period").orderByAsc("period");

        //查询结果返回
        List<Map<String, Object>> resultList = pictureService.getBaseMapper().selectMaps(pictureQueryWrapper);

        return resultList.stream()
                .map(result ->{
                    String period =  result.get("period").toString();
                    Long count = ((Number) result.get("count")).longValue();
                    return new SpaceUserAnalyzeResponse(period,count);
                }).collect(Collectors.toList());


    }

    @Override
    public List<Space> getSpaceRankAnalyze(SpaceRankAnalyzeRequest spaceRankAnalyzeRequest, User loginUser) {
        ThrowUtils.throwIf(spaceRankAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(!userService.isAdmin(loginUser),ErrorCode.PARAMS_ERROR);
        //查询条件
        QueryWrapper<Space> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id","spaceName","userId","totalSize")
                .orderByDesc("totalSize")
                .last("limit "+spaceRankAnalyzeRequest.getTopN());
        //查询结果返回
        return spaceService.list(queryWrapper);
    }

    private void checkSpaceAnalyzeAuth(SpaceAnalyzeRequest spaceAnalyzeRequest, User loginUser) {
        // 检查权限
        if (spaceAnalyzeRequest.isQueryAll() || spaceAnalyzeRequest.isQueryPublic()) {
            // 全空间分析或者公共图库权限校验：仅管理员可访问
            ThrowUtils.throwIf(!userService.isAdmin(loginUser), ErrorCode.NO_AUTH_ERROR, "无权访问公共图库");
        } else {
            // 私有空间权限校验
            Long spaceId = spaceAnalyzeRequest.getSpaceId();
            ThrowUtils.throwIf(spaceId == null || spaceId <= 0, ErrorCode.PARAMS_ERROR);
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
            spaceService.checkSpaceAuth(loginUser, space);
        }
    }

    private static void fillAnalyzeQueryWrapper(SpaceAnalyzeRequest spaceAnalyzeRequest, QueryWrapper<Picture> queryWrapper) {
        if (spaceAnalyzeRequest.isQueryAll()) {
            return;
        }
        if (spaceAnalyzeRequest.isQueryPublic()) {
            queryWrapper.isNull("spaceId");
            return;
        }
        Long spaceId = spaceAnalyzeRequest.getSpaceId();
        if (spaceId != null) {
            queryWrapper.eq("spaceId", spaceId);
            return;
        }
        throw new BusinessException(ErrorCode.PARAMS_ERROR, "未指定查询范围");
    }



}
